#include "commons.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void create_console() {
    emu = ( CONSOLE* )malloc( sizeof(CONSOLE) );
    emu->m6502 = ( M6502* )malloc( sizeof(M6502) );
    memset( emu->ram, 0, 0x10000 );
    memset( emu->vram, 0, 0x4000 );
    memset( emu->sram, 0, 0x100 );
    reset_m6502();
    emu->ppu = ( PPU* )malloc( sizeof(PPU) );
    reset_ppu();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void load_file( const char path[] ) {
    FILE* fp = fopen( path, "rb" );
    if( !fp ) {
        printf( "\nError: no se encontro el archivo <%s>", path );
        exit( 0 );
    }
    fseek( fp, 4, 0 );
    int rom_banks = fgetc( fp );
    fseek( fp, 6, 0 );
    emu->ppu->mirroring = ( fgetc(fp) & 0x1 ? MIRRORING_VERTICAL : MIRRORING_HORIZONTAL );
    fseek( fp, 16, 0 );
    switch( rom_banks ) {
        case 1:
            fread( &emu->ram[0x8000], 1, 0x4000, fp );
            memcpy( &emu->ram[0xc000], &emu->ram[0x8000], 0x4000 );
            break;
        case 2:
            fread( &emu->ram[0x8000], 1, 0x8000, fp );
            break;
        default:
            fclose( fp );
            printf("\nError: demasiados bancos de memoria PRG-ROM");
            exit( 0 );
    }
    fread( emu->vram, 1, 0x2000, fp );
    fclose( fp );
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void run() {
    int cycles = 0;
    
    reset_m6502();
    
    for( ;; ) {
        if( kbhit() ) {
            if( getch() == 27 ) exit( 0 );
        }

        while( cycles <= 114 ) {
            execute_opcode( fetch_opcode() );
            cycles += emu->m6502->ticks;
        }
        cycles -= 114;
        run_scanline();
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void handle_interrupt( int interrupt ) {
    switch( interrupt ) {
        case INTERRUPT_NMI: nmi_interrupt(); break;
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////